Мастерская Delphi программирования. | |||||||||||||
| |||||||||||||
Определение принтера по умолчанию.
Как выбрать принтер по умолчанию с помощью TPrinter вы конечно знаете. Если нет, открою Вам маленький секрет - надо присвоить свойству PrinterIndex значение -1. А вы не задумывались, что при этом происходит внутри класса Tprinter? Давайте вместе разберемся. Очевидно, что раз мы присваиваем значение свойству класса, необходимо рассмотреть метод, который отвечает за установку этого свойства. Ниже приведен код метода TPrinter.SetPrinterIndex. procedure TPrinter.SetPrinterIndex(Value: Integer); begin CheckPrinting(False); if (Value = -1) or (PrinterIndex = -1) then SetToDefaultPrinter else if (Value < 0) or (Value >= Printers.Count) then RaiseError(SPrinterIndexError); FPrinterIndex := Value; FreeFonts; SetState(psNoHandle); end; Что сразу бросается в глаза - это вызов приватного метода SetToDefaultPrinter когда вы устанавливаете свойство в -1. Очевидно, он и отвечает за выбор принтера, который используется системой по умолчанию. Рассмотрим, что этот метод делает. procedure TPrinter.SetToDefaultPrinter; var I: Integer; ByteCnt, StructCnt: DWORD; DefaultPrinter: array[0..79] of Char; Cur, Device: PChar; PrinterInfo: PPrinterInfo5; begin ByteCnt := 0; StructCnt := 0; if not EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, nil, 0, ByteCnt, StructCnt) and (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then begin // With no printers installed, Win95/98 fails above with "Invalid filename". // NT succeeds and returns a StructCnt of zero. if GetLastError = ERROR_INVALID_NAME then RaiseError(SNoDefaultPrinter) else RaiseLastWin32Error; end; PrinterInfo := AllocMem(ByteCnt); try EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, PrinterInfo, ByteCnt, ByteCnt, StructCnt); if StructCnt > 0 then Device := PrinterInfo.pPrinterName else begin GetProfileString('windows', 'device', '', DefaultPrinter, SizeOf(DefaultPrinter) - 1); Cur := DefaultPrinter; Device := FetchStr(Cur); end; with Printers do for I := 0 to Count-1 do begin if TPrinterDevice(Objects[I]).Device = Device then begin with TPrinterDevice(Objects[I]) do SetPrinter(PChar(Device), PChar(Driver), PChar(Port), 0); Exit; end; end; finally FreeMem(PrinterInfo); end; RaiseError(SNoDefaultPrinter); end; В первых строках своего кода метод определяет - "А стоит ли работать дальше? Может быть, в системе нет установленных принтеров". if not EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, nil, 0, ByteCnt, StructCnt) and (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then begin // With no printers installed, Win95/98 fails above with "Invalid filename". // NT succeeds and returns a StructCnt of zero. if GetLastError = ERROR_INVALID_NAME then RaiseError(SNoDefaultPrinter) else RaiseLastWin32Error; end;Определяется это вызовом функции API EnumPrinters с параметром PRINTER_ENUM_DEFAULT. Одновременно определяется размер буфера, который будет содержать информацию о принтере. Размер буфера возвращается в переменной ByteCnt. Хочется отметить что, первый вызов EnumPrinters всегда заканчивается ошибкой. Вызывая GetLastError, определяем тип ошибки. В нашем случае это может быть ERROR_INSUFFICIENT_BUFFER - неверно задан размер буфера, или ERROR_INVALID_NAME - в Win98 не установлено ни одного принтера. В случае Win NT о наличии установленных принтеров сообщает переменная StructCnt. Если она равна 0, в Win NT не установлены принтеры. После того как разобрались с наличием принтеров и размером буфера снова вызываем EnumPrinters, чтобы наконец-то узнать какой принтер система использует по умолчанию. EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, PrinterInfo, ByteCnt, ByteCnt, StructCnt);О том, что такой принтер существует, сигнализирует переменная StructCnt. Если она не равна 0, значит, функция EnumPrinters вернула информацию о принтере. Сохраняем его имя в переменной Device. В противном случае пытаемся прочитать нужную информацию из файла Win.ini. if StructCnt > 0 then Device := PrinterInfo.pPrinterName else begin GetProfileString('windows', 'device', '', DefaultPrinter, SizeOf(DefaultPrinter) - 1); Cur := DefaultPrinter; Device := FetchStr(Cur); end; Остались сущие пустяки. Перебирая список принтеров, сравниваем их имена. При совпадении имен, делаем принтер текущем, вызвав метод SetPrinter. with Printers do for I := 0 to Count-1 do begin if TPrinterDevice(Objects[I]).Device = Device then begin with TPrinterDevice(Objects[I]) do SetPrinter(PChar(Device), PChar(Driver), PChar(Port), 0); Exit; end; end;Не будем подробно рассматривать работу метода. Единственное на что следует обратить внимание - это строка: ... FPrinterIndex := J; ... Из сказанного выше можно сделать вывод: Значение свойства PrinterIndex никогда не установится в -1. После завершения работы метода значение PrinterIndex будет содержать индекс принтера используемого системой по умолчанию не равного -1. Таким образом найти имя принтера по умолчанию из списка принтеров класса TPrinter не составляет больших усилий. Попробуйте определить принтер по умолчанию на своей машине, скомпилировав пример. | |||||||||||||
| |||||||||||||
http://www.valler.narod.ru |